﻿// <copyright file="PictureBoxEx.cs" company="Embedded Media Framework">
// Published unter MS-PL at http://www.codeplex.com/emf
// Copyright (c) 2008 All Right Reserved
// </copyright>
// <author>Ulrich 'connex' Strauss</author>
// <email>http://www.codeplex.com/emf/</email>
// <date>2008-11-13</date>

using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using EMF.Forms.Utils;

namespace EMF.Forms.Controls
{
    /// <summary>
    /// An extended PictureBox which supports alphablending and transparent images
    /// </summary>
    public partial class PictureBoxEx : PictureBox, ISupportInitialize
    {
        /// <summary>
        /// Alpha blending Factor
        /// </summary>
        private byte myAlphaFactor = 0;

        /// <summary>
        /// Color to make transparent
        /// </summary>
        private Color myTransparentColor = Color.Empty;

        /// <summary>
        /// Default Constructor
        /// </summary>
        public PictureBoxEx()
            : base()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Gets or sets Alphablending factor for the image. 
        /// </summary>
        public byte AlphaFactor
        {
            get
            {
                return this.myAlphaFactor;
            }

            set
            {
                if ((value != 0) && (!this.myTransparentColor.IsEmpty))
                {
                    throw new ArgumentException("Transparency & Alphablending are exclusive");
                }

                this.myAlphaFactor = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// Gets or sets the Color to make transparent when drawing
        /// </summary>
        public Color TransparentColor
        {
            get
            {
                return this.myTransparentColor;
            }

            set
            {
                if ((value != Color.Empty) && (AlphaFactor != 0))
                {
                    throw new ArgumentException("Transparency & Alphablending are exclusive");
                }

                this.myTransparentColor = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// Gets Target image rectangle according to <seealso cref="PictureBox.SizeMode"/>
        /// </summary>
        private Rectangle _ImageRectangle
        {
            get
            {
                Rectangle rectangle = new Rectangle(0, 0, 0, 0);
                if (this.Image != null)
                {
                    switch (this.SizeMode)
                    {
                        case PictureBoxSizeMode.Normal:
                            rectangle.Size = this.Image.Size;
                            return rectangle;

                        case PictureBoxSizeMode.StretchImage:
                            rectangle.Size = this.ClientSize;
                            return rectangle;

                        case (PictureBoxSizeMode)2:
                            return rectangle;

                        case PictureBoxSizeMode.CenterImage:
                            {
                                rectangle.Size = this.Image.Size;
                                Size clientSize = this.ClientSize;
                                rectangle.X = (clientSize.Width - rectangle.Width) / 2;
                                rectangle.Y = (clientSize.Height - rectangle.Height) / 2;
                                return rectangle;
                            }
                    }
                }

                return rectangle;
            }
        }

        /// <summary>
        /// Make Image transparent. Trasparent color is at pixel 0,0
        /// </summary>
        public void MakeTransparent()
        {
            this.TransparentColor = GetTransparentColor();
        }

        /// <summary>
        /// Make Image transparent. Trasparent color is at given pixel
        /// </summary>
        /// <param name="x">X-Coordinate of the pixel</param>
        /// <param name="y">Y-Coordinate of the pixel</param>
        public void MakeTransparent(int x, int y)
        {
            this.TransparentColor = GetTransparentColor(x, y);
        }

        /// <summary>
        /// Draw background of control
        /// </summary>
        /// <param name="e">PaintEventArgs</param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            if (((AlphaFactor == 0) && TransparentColor.IsEmpty) || (!(this.Image is Bitmap)))
            {
                base.OnPaintBackground(e);
                return;
            }

            // Only draw a Background if Alphablending is disabled
            if (AlphaFactor == 0)
            {
                using (Region region = new Region(this.ClientRectangle))
                using (Brush brush = new SolidBrush(this.BackColor))
                {
                    e.Graphics.FillRegion(brush, region);
                }
            }
        }

        /// <summary>
        /// Paint the control
        /// </summary>
        /// <param name="e">PaintEventArgs</param>
        protected override void OnPaint(PaintEventArgs e)
        {         
            if (((AlphaFactor == 0) && this.myTransparentColor.IsEmpty) || (!(this.Image is Bitmap)))
            {
                base.OnPaint(e);
                return;
            }

            if (AlphaFactor != 0)
            {
                Rectangle tmp = this._ImageRectangle;
                ControlsHelper.DrawAlphaBlended(e.Graphics, this.Image as Bitmap, AlphaFactor, tmp.X, tmp.Y, tmp.Width, tmp.Height);
                return;
            }

            ImageAttributes attrib = new ImageAttributes();

            attrib.SetColorKey(myTransparentColor, myTransparentColor);
            e.Graphics.DrawImage(this.Image, this._ImageRectangle, 0, 0, this.Image.Width, this.Image.Height, GraphicsUnit.Pixel, attrib);
        }

        /// <summary>
        /// Gets Color at pixel 0,0
        /// </summary>
        /// <returns>Color</returns>
        private Color GetTransparentColor()
        {
            return GetTransparentColor(0, 0);
        }

        /// <summary>
        /// Get Color at specified pixel
        /// </summary>
        /// <param name="x">X-Coordinate</param>
        /// <param name="y">Y-Coordinate</param>
        /// <returns>Color</returns>
        private Color GetTransparentColor(int x, int y)
        {
            if (this.Image == null)
            {
                return Color.Empty;
            }

            if (!(this.Image is Bitmap))
            {
                return Color.Empty;
            }

            Bitmap tmp = this.Image as Bitmap;
            return tmp.GetPixel(x, y);
        }

        #region ISupportInitialize Members
        /// <summary>
        /// Implements ISupportInitialize.BeginInit
        /// </summary>
        void ISupportInitialize.BeginInit()
        {
        }

        /// <summary>
        /// Implements ISupportInitialize.EndInit
        /// </summary>
        void ISupportInitialize.EndInit()
        {
        }

        #endregion
    }
}